package znet

import (
	"errors"
	logging "github.com/sirupsen/logrus"
	"io"
	"net"
	"sync"
	"webdemo/src/zinx/utils"
	"webdemo/src/zinx/zinterface"
)

// 链接模块
type Connection struct {
	// 当前conn所属server
	TcpServer zinterface.IServer
	Conn      *net.TCPConn
	ConnID    uint32
	isClose   bool
	// 当前链接的处理方法
	//handAPI zinterface.HandFunc
	ExitChan chan bool

	MsgHandle zinterface.IMsgHandle

	MsgChan chan []byte
	// 连接属性
	property map[string]interface{}
	// 保护连接属性的锁
	propertyLock sync.RWMutex
}

// 初始化链接
func NewConnection(server zinterface.IServer, conn *net.TCPConn, ConnID uint32, msgHandle zinterface.IMsgHandle) *Connection {
	c := &Connection{
		TcpServer: server,
		Conn:      conn,
		ConnID:    ConnID,
		MsgHandle: msgHandle,
		isClose:   false,
		ExitChan:  make(chan bool, 1),
		MsgChan:   make(chan []byte),
		property:  make(map[string]interface{}),
	}
	// 将conn 加入到connManager中
	c.TcpServer.GetConnMgr().Add(c)
	return c
}

func (c *Connection) StartWriter() {
	logging.Info("[Connection][StartWriter] begin...")
	defer logging.Info("[Connection][StartWriter] end...")
	for true {
		select {
		case data := <-c.MsgChan:
			// 发送消息到客户端
			if _, err := c.Conn.Write(data); err != nil {
				logging.Info("[Connection][StartWriter] Conn.Write err is ", err)
				return
			}
		case <-c.ExitChan:
			// 代表reader 退出
			return
		}
	}
}
func (c *Connection) StartReader() {
	logging.Info("[Connection][StartReader] begin...")
	defer logging.Info("[Connection][StartReader] end...")
	defer c.Stop()
	for true {
		// 读取数据到buf
		/*buf := make([]byte, 512)
		_, err := c.Conn.Read(buf)
		if err != nil {
			logging.Error("[Connection][StartReader] Conn.Read err is ", err)
			continue
		}*/
		// 创建拆包对象
		dp := NewDataPack()

		headData := make([]byte, dp.GetHeadLen())
		_, err := io.ReadFull(c.GetTCPConnection(), headData)
		if err != nil {
			logging.Error("[Connection][StartReader] io.ReadFull err is ", err)
			break
		}
		msg, err := dp.Unpack(headData)
		if err != nil {
			logging.Error("[Connection][StartReader] dp.Unpack err is ", err)
			break
		}

		if msg.GetDataLen() > 0 {
			data := make([]byte, msg.GetDataLen())
			if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
				logging.Error("[Connection][StartReader]  io.ReadFull err is ", err)
				break
			}
			msg.SetData(data)
		}

		// 处理绑定的 handAPI 业务
		// 通过路由调用
		request := Request{
			conn: c,
			msg:  msg,
		}

		if utils.GlobalObj.WorkerPoolSize > 0 {
			c.MsgHandle.SendMsgToTaskQueue(&request)
		} else {
			go c.MsgHandle.DoMsgHandler(&request)
		}

		/*if err := c.handAPI(c.Conn, buf, cnt);err != nil {
			logging.Error("[Connection][StartReader] Conn.handAPI err is ",err)
			break
		}*/
	}
}

// 启动链接
func (c *Connection) Start() {
	logging.Info("[Connection][Start] begin...")
	// 从当前链接读取数据
	go c.StartReader()
	// 从当前链接写数据
	go c.StartWriter()

	// 调用hook方法
	c.TcpServer.CallOnConnStart(c)
}

// 停止链接
func (c *Connection) Stop() {
	logging.Info("[Connection][Stop] begin...")
	if c.isClose == true {
		logging.Info("[Connection][Stop] conn isClose")
		return
	}
	c.isClose = true

	// 关闭前调用hook
	c.TcpServer.CallOnConnStop(c)

	c.Conn.Close()

	c.ExitChan <- true

	c.TcpServer.GetConnMgr().Remove(c)

	close(c.ExitChan)
	close(c.MsgChan)
	logging.Info("[Connection][Stop] end...")
}

// 获取链接
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

// 获取链接id
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

// 获取远程ip
func (c *Connection) RemoteAddr() net.Addr {
	return c.RemoteAddr()
}

// 发送数据
/*func (c *Connection) Send(data []byte) error {
	return nil
}*/

func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.isClose {
		return errors.New("c.isClose")
	}
	// 将data 封包
	dp := NewDataPack()
	msgPackage := NewMsgPackage(msgId, data)
	binaryMsg, err := dp.Pack(msgPackage)
	if err != nil {
		logging.Error("[Connection][SendMsg] dp.Pack err is ", err)
		return err
	}

	// 消息写入chan 不再直接发送
	c.MsgChan <- binaryMsg
	/*_, err = c.Conn.Write(binaryMsg)
	if err != nil {
		logging.Error("[Connection][SendMsg] Conn.Write err is ", err)
		return err
	}*/
	return nil
}

func (c *Connection) SetProperty(key string, value interface{}) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()
	c.property[key] = value
}

func (c *Connection) GetProperty(key string) (interface{}, error) {
	c.propertyLock.RLock()
	defer c.propertyLock.RUnlock()
	if value, ok := c.property[key]; ok {
		return value, nil
	}
	return nil, errors.New("no property")
}

func (c *Connection) RemoveProperty(key string) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()
	delete(c.property, key)
}
